package com.lzw.breezeNovel.WebAdmin.service.impl;


import com.lzw.breezeNovel.WebAdmin.mapper.AdvertisementMapper;
import com.lzw.breezeNovel.WebAdmin.service.AdvertisementService;
import com.lzw.breezeNovel.WebAdmin.vo.AdvertisementVo;
import com.lzw.breezeNovel.common.exception.BaseException;
import com.lzw.breezeNovel.model.entity.pojo.novel.Advertisement;
import com.lzw.breezeNovel.model.entity.query.PaginationResultQuery;
import com.lzw.breezeNovel.model.entity.query.SimplePage;
import com.lzw.breezeNovel.model.enums.novel.AdvertisementStatus;
import com.lzw.breezeNovel.model.enums.novel.Advertisementpostition;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;


/**
 * 广告管理
 *
 */
@Slf4j
@Service
@SuppressWarnings("all")
public class AdvertisementServiceImpl implements AdvertisementService {

    /**
     * 注入广告管理mapper
     */
    @Resource
    private AdvertisementMapper advertisementMapper;

    // 使用ThreadLocal确保日期格式化的线程安全
    private static final ThreadLocal<DateFormat> DATE_FORMATTER = ThreadLocal.withInitial(
            () -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    );


    /**
     * 添加广告
     * @param advertisement
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addAdvertisement(@NotNull Advertisement advertisement) {
        //获取广告投放时间
        Integer day = advertisement.getDay();
        //广告开始时间
        Date date = new Date();
        advertisement.setStartTime(date);
        //计算广告结束时间
        advertisement.setEndTime(new Date(date.getTime() + day * 24 * 60 * 60 * 1000));
        //新增广告
        advertisementMapper.insert(advertisement);
    }
    /**
     * 获取所有的广告
     * @param advertisement
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public PaginationResultQuery<AdvertisementVo> getAllAdvertisement(@NotNull Advertisement advertisement) {
        // 处理分页参数并设置默认值
        int pageNo = Optional.ofNullable(advertisement.getPageNo())
                .map(p -> Math.max(p, 1))
                .orElse(1);
        int pageSize = Optional.ofNullable(advertisement.getPageSize())
                .map(ps -> Math.max(ps, 10))
                .orElse(10);

        // 查询总记录数
        Long totalCount = advertisementMapper.selectCount();
        if (totalCount == 0) {
            return new PaginationResultQuery<>(0, pageSize, pageNo, 0, Collections.emptyList());
        }

        // 创建分页对象并进行校验
        validateCount(totalCount);
        SimplePage simplePage = new SimplePage(pageNo, totalCount.intValue(), pageSize);
        simplePage.action();

        // 设置分页参数并执行查询
        advertisement.setSimplePage(simplePage);
        List<Advertisement> advertisements = advertisementMapper.selectByPage(advertisement);

        // 转换并返回结果
        return new PaginationResultQuery<>(
                simplePage.getPageTotal(),
                pageSize,
                pageNo,
                totalCount.intValue(),
                convertToVoList(advertisements)
        );
    }

    /**
     * 校验总数量
     * @param count
     */
    private void validateCount(Long count) {
        if (count > Integer.MAX_VALUE) {
            throw new BaseException(500,"查询超出了系统限制");
        }
    }

    /**
     * 批量转换Vo对象
     * @param advertisements
     * @return
     */
    private List<AdvertisementVo> convertToVoList(@NotNull List<Advertisement> advertisements) {
        return advertisements.stream()
                .map(this::convertToVo)
                .collect(Collectors.toList());
    }

    /**
     * 单个转换
     * @param ad
     * @return
     */
    @NotNull
    private AdvertisementVo convertToVo(Advertisement ad) {
        AdvertisementVo vo = new AdvertisementVo();
        BeanUtils.copyProperties(ad, vo);
        // 处理广告状态
        vo.setStatus(getStatusDescription(ad.getStatus()));
        // 处理时间格式化
        vo.setStartTime(formatDateTime(ad.getStartTime()));
        vo.setEndTime(formatDateTime(ad.getEndTime()));
        // 处理广告位置
        vo.setPosition(getPositionDescription(ad.getPosition()));
        return vo;
    }

    // 获取状态描述（带空值保护）
    private String getStatusDescription(Integer status) {
        if (status == null) return "未知状态";
        AdvertisementStatus statusEnum = AdvertisementStatus.get(status);
        return statusEnum != null ? statusEnum.getDesc() : "异常状态";
    }

    // 获取位置描述（带空值保护）
    @NotNull
    private String getPositionDescription(Integer position) {
        if (position == null) return "未知位置";
        String desc = Advertisementpostition.getAdvertisementpostition(position);
        return desc != null ? desc : "异常位置";
    }
    // 日期格式化方法（带空值保护）
    @NotNull
    private String formatDateTime(Date date) {
        if (date == null) return "";
        try {
            return DATE_FORMATTER.get().format(date);
        } catch (Exception e) {
            log.warn("日期格式化异常", e);
            return "";
        }
    }

    /**
     * 更新广告详情
     * @param advertisement
     */
    @SneakyThrows
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAdvertisement(@NotNull Advertisement advertisement) {
        //根据广告id查询广告信息
        String time = advertisementMapper.selectById(advertisement.getId());
        Date parse = DATE_FORMATTER.get().parse(time);
        //判断是否修改了广告的时间
        if (!time.equals(advertisement.getStartTime().toString())) {
            //重新设置广告时间
            Integer day = advertisement.getDay();
            //计算时间1
            Date date = calculateEndTime(parse, day);
            //重新设置时间
            advertisement.setEndTime(date);
        }
        advertisementMapper.updateAdvertisement(advertisement);
    }


    /**
     * 计算结束时间的方法
     * @param startTime
     * @param days
     * @return
     */
    @NotNull
    @Contract("_, _ -> new")
    private Date calculateEndTime(@NotNull Date startTime, int days) {
        // 将 Date 转换为毫秒数
        long startTimeMillis = startTime.getTime();
        // 一天的毫秒数
        long oneDayMillis = 24 * 60 * 60 * 1000;
        // 计算结束时间的毫秒数
        long endTimeMillis = startTimeMillis + days * oneDayMillis;
        // 将毫秒数转换为 Date 对象
        return new Date(endTimeMillis);
    }

    /**
     * 删除广告
     * @param id
     */
    @Override
    public void deleteAdvertisement(Integer id) {
        advertisementMapper.deleteAdvertisement(id);
    }

    /**
     * 暂停广告
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pauseAdvertisement(Integer id) {
        Advertisement advertisement = advertisementMapper.select(id);
        //获取广告结束时间
        Date endTime = advertisement.getEndTime();
        //获取当前时间
        Date date = new Date();
        //判断当前时间是否大于广告结束时间
        if (date.after(endTime)) {
            throw new BaseException(500,"广告已过期，无法暂停");
        }
        //计算还剩下多少时间
        long times = endTime.getTime() - date.getTime();
        advertisementMapper.pauseAdvertisement(id, Math.toIntExact(times));
    }

    /**
     * 恢复广告
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resumeAdvertisement(Integer id) {
        Advertisement advertisement = advertisementMapper.select(id);
        //获取当前时间
        Date date = new Date();
        //获取暂停的时间
        Integer time = advertisement.getTime();
        //判断是否为空
        if(time == null){
            throw new BaseException(500,"广告未暂停，无法恢复");
        }
        //计算恢复的时间
        Date d = new Date(date.getTime() + time);
        advertisementMapper.resumeAdvertisement(id,d);
    }

    /**
     * 批量删除广告
     * @param ids
     */
    @Override
    public void deleteAdvertisementBatch(Integer[] ids) {
        advertisementMapper.deleteAdvertisementBatch(ids);
    }
}
